/*
*********************************************************************************************************
*                                       LK_WDR
*
*                             (c) Copyright 2015;
*
*                   All rights reserved.  Protected by international copyright laws.
*                   Knowledge of the source code may not be used to write a similar
*                   product.  This file may only be used in accordance with a license
*                   and should not be redistributed in any way.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                     the Application of W5500 Task
*                             ST Microelectronics STM32 with the STM32F407IGT6
*
* Filename      : app_W5500.c
* Version       : V1.0.0
* Programmer(s) : ZhangYu
*********************************************************************************************************
*/
#include "includes.h"

#define DATA_BUF_SIZE   2048
uint8_t gDATABUF[DATA_BUF_SIZE];
static int32_t reLinkTickCnt = -1;
static uint8_t DHAR_SOCK[TRDP_SEND_IP_CNT+TRDP_RECV_IP_CNT][6];
static uint8_t issocketOK[TRDP_SEND_IP_CNT+TRDP_RECV_IP_CNT];
//-------public  variable defines----------------
//-------private variables defines----------------
//-------internal function declare-----------------
static void initTaskWork(void);

/*******************************************************************************
* Function Name  : initDiskMemory
* Description    : set Disk Memory data to default value
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void initTaskWork(void)
{
	int i = 0;
	for(i=0; i<(TRDP_SEND_IP_CNT+TRDP_RECV_IP_CNT); i++){

		DHAR_SOCK[i][0] = 0x01;
		DHAR_SOCK[i][1] = 0x00;
		DHAR_SOCK[i][2] = 0x5e;
		
		DHAR_SOCK[i][3] = TRDP_GRP_IP[i][1] & 0x7f;
		DHAR_SOCK[i][4] = TRDP_GRP_IP[i][2];
		DHAR_SOCK[i][5] = TRDP_GRP_IP[i][3];
		
		issocketOK[i] = 0;
	}
	
	W5500Init((uint8_t *)p_gSysUserRegs->MR_Para.IP_ADDR_RDNC, (uint8_t *)p_gSysUserRegs->MR_Para.NETMASK_ADDR_RDNC, (uint8_t *)p_gSysUserRegs->MR_Para.GW_ADDR_RDNC, (uint8_t *)p_gSysUserRegs->MR_Para.MAC_ADDR_RDNC);
	
	//AUTO NEG config set	
#if USE_AUTONEG == 0
		setPHYCFGR(0x58);
		vTaskDelay(10);
		setPHYCFGR(0xD8);
		vTaskDelay(10);
#endif
}

static void configMutliCastIP_PORT(uint8_t s, uint8_t *addr, uint16_t port)
{

  IINCHIP_WRITE( Sn_DIPR0(s), addr[0]);
  IINCHIP_WRITE( Sn_DIPR1(s), addr[1]);
  IINCHIP_WRITE( Sn_DIPR2(s), addr[2]);
  IINCHIP_WRITE( Sn_DIPR3(s), addr[3]);

  IINCHIP_WRITE( Sn_DHAR0(s), DHAR_SOCK[s][0]);
  IINCHIP_WRITE( Sn_DHAR1(s), DHAR_SOCK[s][1]);
  IINCHIP_WRITE( Sn_DHAR2(s), DHAR_SOCK[s][2]);
  IINCHIP_WRITE( Sn_DHAR3(s), DHAR_SOCK[s][3]);
  IINCHIP_WRITE( Sn_DHAR4(s), DHAR_SOCK[s][4]);
  IINCHIP_WRITE( Sn_DHAR5(s), DHAR_SOCK[s][5]);


  IINCHIP_WRITE( Sn_DPORT0(s),(uint8_t)((port & 0xff00) >> 8));
  IINCHIP_WRITE( Sn_DPORT1(s),(uint8_t)(port & 0x00ff));
}

static void processW5500Socket(uint8_t s, uint8_t mode)
{
	static ETH_MSG recvMsg;
	uint8_t DstIP[]={192,168,8,123};
	uint16_t DstPort = 0, recvSize = 0;
	uint8_t net_state, i=0;

	net_state=getSn_SR(s);		//get socket state
	if(net_state == SOCK_CLOSE_WAIT){
		//socket is wating to be closed
		disconnect(s);
	}else if(net_state == SOCK_CLOSED){
		//now socket has been closed and we should open it now
		for(i=0; i<(TRDP_SEND_IP_CNT+TRDP_RECV_IP_CNT); i++){
			if(i == s){
				configMutliCastIP_PORT(s, (uint8_t *)&TRDP_GRP_IP[i][0],  UDP_TRDP_PD_PORT);
				issocketOK[s]  = socket(s,Sn_MR_UDP,UDP_TRDP_PD_PORT,SF_MULTI_ENABLE);
				if(issocketOK[s] != 0){
					vTaskDelay(1);
				}
			}
		}
	}else if(net_state == SOCK_UDP){
		while( xQueueReceive( xQue_W5500, &recvMsg, ( TickType_t ) 0 ) ){
			if(issocketOK[s] == 1){
				if(s == recvMsg.id){
					//we send it out
					sendMuliTo(s,recvMsg.data, (uint16_t)recvMsg.len);
				}else{
					//we put it back
					xQueueSend( xQue_W5500, ( void * ) &recvMsg, ( TickType_t ) 1 );
					break;
				}
			}
		}

		if(s >= TRDP_SEND_IP_CNT){
			recvSize = recvfrom(s, gDATABUF, DATA_BUF_SIZE, DstIP, &DstPort);
			if(recvSize > 0)
			{
					trdp_mini_Receive_CallBack(NULL, gDATABUF, recvSize, DstIP, DstPort);
					reLinkTickCnt = 0;
			}
		}
	}
}

uint32_t TRDP_Slave_Send_Message(uint8_t *data, uint16_t size, uint8_t mode)
{
	ETH_MSG msg;

	if((size > 0) && (size < sizeof(msg.data))){
		msg.id = mode;
		msg.len = size;
		memcpy(msg.data, data, size);
		if( xQueueSend( xQue_W5500, ( void * ) &msg, ( TickType_t ) 10 ) != pdPASS ){
			return ERROR;
		}else{
			return OK;
		}
	}

	return ERROR;
}

/*******************************************************************************
* Function Name  : TASK_DISK
* Description    : this task if used for information store
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TASK_W5500( void *pvParameters )
{
	E2PROM_MSG logMsg;
	uint8_t i = 0, phyState = 0;
	uint32_t tickCnt = 0;

	initTaskWork();

    while(1)
    {
    	vTaskDelay(1);
    	tickCnt++;
			
			if((reLinkTickCnt >= 0) && (reLinkTickCnt < 32765)){
				reLinkTickCnt++;
				if(reLinkTickCnt > 2000){
					initTaskWork();
					reLinkTickCnt = -1;
				}
			}
			
    	for(i = 0; i< (TRDP_SEND_IP_CNT+TRDP_RECV_IP_CNT); i++){
    		processW5500Socket(i, i);
    	}

    	if((tickCnt % 500) == 0){
				if(phyState != (getPHYCFGR() & 0x01)){
					phyState = getPHYCFGR() & 0x01;
					logMsg.rtcTime = gRTCtime;
					if( (phyState & 0x01) == 0){
						logMsg.errCode = LOG_ETH1_LINK_DOWN;
						reLinkTickCnt = -1;
					}else{
						logMsg.errCode = LOG_ETH1_LINK_ON;
					}
					xQueueSend(xQue_E2PROM, (void *)&logMsg,  (TickType_t)0);
				}
			}
			
    }
}
